package com.kitten.auth.service.impl;

import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import com.google.common.base.Preconditions;
import com.kitten.auth.constant.RedisKeyConstants;
import com.kitten.auth.constant.RoleConstants;
import com.kitten.auth.domain.dataobject.RoleDO;
import com.kitten.auth.domain.dataobject.UserDO;
import com.kitten.auth.domain.dataobject.UserRoleDO;

import com.kitten.auth.enums.LoginTypeEnum;
import com.kitten.auth.enums.ResponseCodeEnum;
import com.kitten.auth.model.vo.user.UpdatePasswordReqVO;
import com.kitten.auth.model.vo.user.UserLoginReqVO;
import com.kitten.auth.rpc.UserRpcService;
import com.kitten.auth.service.AuthService;
import com.kitten.framework.common.enums.DeletedEnum;
import com.kitten.framework.common.enums.StatusEnum;
import com.kitten.framework.common.exception.BizException;
import com.kitten.framework.common.response.Response;
import com.kitten.framework.common.utils.JsonUtils;
import com.kitten.framework.context.holder.LoginUserContextHolder;
import com.kitten.user.dto.resp.FindUserByPhoneRspDTO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Objects;
import java.util.List;

@Service
@Slf4j
public class AuthServiceImpl implements AuthService {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;


    @Resource(name = "taskExecutor")
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
    @Resource
    private PasswordEncoder passwordEncoder;

    @Autowired
    private UserRpcService userRpcService;


    @Override
    public Response<String> loginAndRegister(UserLoginReqVO userLoginReqVO) {
        String phone = userLoginReqVO.getPhone();
        Integer typeCode = userLoginReqVO.getType();

        LoginTypeEnum loginTypeEnum = LoginTypeEnum.getType(typeCode);
        if (Objects.isNull(loginTypeEnum)) {
            throw new BizException(ResponseCodeEnum.LOGIN_TYPE_ERROR);
        }
        Long userId = null;

        // 判断登录类型
        switch (loginTypeEnum) {
            case VERIFICATION_CODE: // 验证码登录
                String verificationCode = userLoginReqVO.getCode(); // 获取用户提交的验证码 例: 491300

                // 校验入参验证码是否为空
                /**
                 * if (StringUtils.isBlank(verificationCode)) {
                 *                     return Response.fail(ResponseCodeEnum.PARAM_NOT_VALID.getErrorCode(), "验证码不能为空");
                 *                 }
                 */
                Preconditions.checkArgument(StringUtils.isNotBlank(verificationCode), "验证码不能为空");


                // 构建验证码 Redis Key
                String key = RedisKeyConstants.buildVerificationCodeKey(phone);
                // 查询存储在 Redis 中该用户的登录验证码
                String sentCode = (String) redisTemplate.opsForValue().get(key);
                log.info("==> 验证码是否正确, key: {}, sentCode: {}, verificationCode: {}", key, sentCode, verificationCode);
                // 判断用户提交的验证码，与 Redis 中的验证码是否一致
                if (!StringUtils.equals(verificationCode, sentCode)) {
                    throw new BizException(ResponseCodeEnum.VERIFICATION_CODE_NOT_VALID);
                }

                // RPC: 调用用户服务, 注册业务
                Long userIdTmp = userRpcService.registerUser(phone);
                if (Objects.isNull(userIdTmp)) {
                    log.info("==> error");
                    throw new BizException(ResponseCodeEnum.LOGIN_FAILED);
                }
                userId = userIdTmp;
                break;
            case PASSWORD: // 密码登录
                // todo RPC: 调用用户服务, 登录业务
                String password = userLoginReqVO.getPassword();
//                UserDO userDO1 = userDOMapper.selectByPhone(phone); // 根据手机号查询用户
                FindUserByPhoneRspDTO rspDTO = userRpcService.findUserByPhone(phone);

                if (Objects.isNull(rspDTO)) {
                    throw new BizException(ResponseCodeEnum.USER_NOT_EXIST);
                }
                String encodePassword = rspDTO.getPassword(); // 获取用户密文密码
                boolean isPasswordCorrect = passwordEncoder.matches(password, encodePassword);
                // 判断密码是否正确
                if (!isPasswordCorrect) {
                    throw new BizException(ResponseCodeEnum.PHONE_OR_PASSWORD_ERROR);
                }
                log.info("===> 密码正确");
                userId = rspDTO.getId();
                break;
            default:
                break;
        }

        // SaToken 登录用户，并返回 token 令牌
        StpUtil.login(userId);
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
        return Response.success(tokenInfo.tokenValue);
    }

    /**
     * 用户退出登录
     * @return
     */
    @Override
    public Response<?> logout() {
//        Long userId = LoginUserContextHolder.getUserId();

        // 异步线程中获取 userId
        threadPoolTaskExecutor.submit(() -> {
            Long userId = LoginUserContextHolder.getUserId();
            log.info("==> 异步线程中获取 userId: {}", userId);
            StpUtil.logout(userId);
        });

        return Response.success();
    }

    /**
     * 更新密码
     * @param updatePasswordReqVO
     * @return
     */
    @Override
    public Response<?> updatePassword(UpdatePasswordReqVO updatePasswordReqVO) {
        String newPassword = updatePasswordReqVO.getNewPassword();
        String encodePassword = passwordEncoder.encode(newPassword);
//        // 获取当前登录用户 ID
//        Long userId = LoginUserContextHolder.getUserId();
//        UserDO userDO = UserDO.builder()
//                .id(userId)
//                .password(encodePassword)
//                .updateTime(LocalDateTime.now())
//                .build();
        // 更新密码
//        userDOMapper.updateByPrimaryKeySelective(userDO);
        userRpcService.updatePassword(encodePassword);
        // 异步线程中清除 Redis 中的登录信息
        return Response.success();
    }


}
